/* Copyright 2020 Huawei Device Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: liangkz @ https://harmonyos.51cto.com/column/46
 * Date  : 2022.04.01
 *
 */
#include "unistd.h"     //sleep
#include "hdf_base.h"
#include "hdf_io_service_if.h"

#if 0  //HDF_LOGI
#include "hdf_log.h"  // use HDF_LOGI to print log should include this .h
#define HDF_LOG_TAG led_green
#else  //HILOG_INFO
#include "hilog/log.h"  // use HILOG_INFO to print log should include this .h
#endif

#undef  LOG_TAG
#undef  LOG_DOMAIN
#define LOG_TAG    "led_grn"
#define LOG_DOMAIN 0xD002021

#define LED_SERVICE_NAME "led_service"

#define LED_GRN_WRITE      2

#define LED_GRN_EVENT_NORMAL  200

#define SUCCESS   0
#define FAILURE  -1

struct LedMsg {
    int32_t cmd_idx;
    int32_t led_mode;
};

static int SendCmd(struct HdfIoService *serv, int32_t cmd_idx, int32_t led_mode)
{
    int ret = SUCCESS;
    struct HdfSBuf *sendBuf = HdfSbufObtainDefaultSize();  //default 256Bytes data
    if (sendBuf == NULL) {
        HILOG_ERROR(LOG_APP, "obtain sendBuf NG");
        return FAILURE;
    }

    struct HdfSBuf *replyBuf = HdfSbufObtainDefaultSize();  //default 256Bytes data
    if (replyBuf == NULL) {
        HILOG_ERROR(LOG_APP, "obtain replyBuf NG");
        ret = FAILURE;
        goto out;
    }

    struct LedMsg msg;
	msg.cmd_idx  = cmd_idx;
	msg.led_mode = led_mode;

	//write a "struct LedMsg" to sendBuf
    if (!HdfSbufWriteBuffer(sendBuf, &msg, sizeof(struct LedMsg))) {
        HILOG_ERROR(LOG_APP, "write sendBuf NG");
        ret = FAILURE;
        goto out;
    }

	HILOG_INFO(LOG_APP, "SendCmd[cmdIdx:%{public}d]: Dispatch(2-LED_GRN_WRITE, mode[%{public}d])", cmd_idx, led_mode);
    //int (*Dispatch)(struct HdfObject *service, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply);
    ret = serv->dispatcher->Dispatch(&serv->object, LED_GRN_WRITE, sendBuf, replyBuf);
    if (ret != SUCCESS) {
        HILOG_ERROR(LOG_APP, "Dispatch(cmd, sendBuf) to service NG");
        goto out;
    }

	//-----------------------------------
	//driver write a "int32_t" to replyBuf, so here read a "int32_t"
    int32_t result = 0;
    if (!HdfSbufReadInt32(replyBuf, &result)) {
        HILOG_ERROR(LOG_APP, "get result from replyBuf NG");
        ret = FAILURE;
        goto out;
    }

	//driver write a "string" to replyBuf, so here read a "string"
	const char* replyStr = HdfSbufReadString(replyBuf);

    HILOG_INFO(LOG_APP, "SendCmd[cmdIdx:%{public}d]: Get reply: result[%{public}d](0-OK,x-NG)+'%{public}s'", cmd_idx, result, replyStr);

out:
    HdfSbufRecycle(sendBuf);
    HdfSbufRecycle(replyBuf);
    return ret;
}

#ifdef OHOS_LITE
int OnDevEventReceived(struct HdfDevEventlistener *listener,
                               struct HdfIoService *service,
                               uint32_t cmdId, struct HdfSBuf *replyBuf)
{
	if (LED_GRN_EVENT_NORMAL == cmdId) {
		//driver write a "int32_t" to replyBuf, so here read a "int32_t"
	    int32_t reportIdx = 0;
	    if (!HdfSbufReadInt32(replyBuf, &reportIdx)) {
	        HILOG_ERROR(LOG_APP, "get reportIdx from replyBuf NG");
	        return FAILURE;
	    }

		//driver write a "string" to replyBuf, so here read a "string"
		const char* reportMsg = HdfSbufReadString(replyBuf);

		//TODO: respond to this event
		(void)service;
	    HILOG_INFO(LOG_APP, "%{public}s: %{public}s: received: EVENT_NORMAL idx[%{public}d]+'%{public}s'",
	             __func__, (char *)listener->priv, reportIdx, reportMsg);
	}
    return SUCCESS;
}
#endif

int main(int argc, char* argv[])
{
	int32_t cmd_cnt = 30;   //default to send cmd_cnt cmd to driver
	int32_t cmd_idx = 0;
	int32_t led_mod = -1;   //0-Off, 1-On, -1||other-defualt to flip
	if (argc >= 2) {
		if (argv[1][0] == '0')
			led_mod = 0;
		else if (argv[1][0] == '1')
			led_mod = 1;
	}

	HILOG_INFO(LOG_APP, "[%s] main enter: %{public}d::[0-Off/1-On/x-flip]", LOG_TAG, led_mod);
	usleep(10);

    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE_NAME);
    if (serv == NULL) {
        HILOG_ERROR(LOG_APP, "get service %{public}s NG", LED_SERVICE_NAME);
        return FAILURE;
    }

#ifdef OHOS_LITE
    static struct HdfDevEventlistener listener = {
        .onReceive = OnDevEventReceived,
        .priv = "Led_Green_Event"
    };

    if (HdfDeviceRegisterEventListener(serv, &listener) != SUCCESS) {
        HILOG_ERROR(LOG_APP, "register event listener NG");
        return FAILURE;
    }
#endif

	switch (led_mod)
	{
	case 0:  // set LED OFF
	case 1:  // set LED ON
		if (SUCCESS != SendCmd(serv, cmd_idx, led_mod)) {
			HILOG_ERROR(LOG_APP, "SendCmd[cmdIdx:%{public}d] NG", cmd_idx);
			return FAILURE;
        }
		break;
	default:  // set LED ON/OFF flashing cmd_cnt times
	    while(cmd_idx < cmd_cnt) {
			cmd_idx ++;

			HILOG_INFO(LOG_APP, "SendCmd[cmdIdx:%{public}d]:----------", cmd_idx);
			if (SUCCESS != SendCmd(serv, cmd_idx, led_mod)) {
	            HILOG_ERROR(LOG_APP, "SendCmd[cmdIdx:%{public}d] NG", cmd_idx);
	            return FAILURE;
	        }
			HILOG_INFO(LOG_APP, "SendCmd[cmdIdx:%{public}d]:++++++++++", cmd_idx);

	        sleep(3);
	    }
	}

#ifdef OHOS_LITE
    if (HdfDeviceUnregisterEventListener(serv, &listener)) {
        HILOG_ERROR(LOG_APP, "unregister listener NG");
        return FAILURE;
    }
#endif

    HdfIoServiceRecycle(serv);
	HILOG_INFO(LOG_APP, "[%s] main exit.", LOG_TAG);

    return SUCCESS;
}
